<?php


namespace chick1993\util;


class Tree
{
    protected $data;
    protected $idKey  = 'id';
    protected $pidKey = 'pid';
    protected $childKey = 'children';
    protected $levelKey = null;
    protected $level     = 0;
    protected $remove = [];
    protected $pid = null;

    protected function __construct(array $data)
    {
        $this->data = $data;
    }

    /**
     * 初始化设置数据
     * @param array $data
     * @return static
     */
    static public function data(array $data): self
    {
        return new static($data);
    }

    /**
     * 设置最顶级pid限制值
     * @param $id
     * @return $this
     */
    public function mustPid($id): self
    {
        $this->pid = $id;
        return $this;
    }

    /**
     * 获取树状数据
     * @return array
     */
    public function get(): array
    {
        $rawArr = $this->data;
        $id = $this->idKey;
        $pid = $this->pidKey;
        $child = $this->childKey;
        $remove = array_flip($this->remove);
        $tree = [];

        if (empty($rawArr)) return [];
        $map = array_column($rawArr, null, $id);
        foreach ($rawArr as $item) {
            $map[$item[$id]] = array_diff_key($map[$item[$id]], $remove);
            if (isset($item[$pid]) && isset($map[$item[$pid]])) {
                $map[$item[$pid]][$child][] = &$map[$item[$id]];
            } else {
                if (isset($this->pid) && $item[$pid] != $this->pid) {
                    continue;
                } else {
                    $tree[] = &$map[$item[$id]];
                }
            }
        }
        unset($map);
        if (!empty($this->levelKey)) {
            $this->_level($tree);
        }
        return $tree;
    }

    protected function _level(&$treeData)
    {
        foreach ($treeData as &$attr) {
            $attr[$this->levelKey] = $attr[$this->levelKey] ?? $this->level;
            if (!empty($attr[$this->childKey])) {
                foreach ($attr[$this->childKey] as &$child) {
                    $child[$this->levelKey] = $attr[$this->levelKey] + 1;
                }
                $this->_level($attr[$this->childKey]);
            }
        }
    }

    /**
     * 设置需要移除的字段
     * @param string|array $field
     * @return $this
     */
    public function remove($field = ''): self
    {
        if (is_string($field)) {
            $field = explode(',', $field);
        }
        foreach ($field as $k => &$item) {
            $field[$k] = (string)$item;
        }
        $this->remove = array_values($field);
        return $this;
    }

    /**
     * 设置主键名
     * @param string $idKey
     * @return $this
     */
    public function id(string $idKey): self
    {
        $this->idKey = $idKey ?: $this->idKey;
        return $this;
    }

    /**
     * 设置关联键名
     * @param string $pidKey
     * @return $this
     */
    public function pid(string $pidKey): self
    {
        $this->pidKey = $pidKey ?: $this->pidKey;
        return $this;
    }

    /**
     * 设置子级数据键名
     * @param string $childKey
     * @return $this
     */
    public function child(string $childKey): self
    {
        $this->childKey = $childKey ?: $this->childKey;
        return $this;
    }

    /**
     * 设置当前等级键名
     * @param string $levelKey
     * @param int $level
     * @return $this
     */
    public function level(string $levelKey, int $level = 0): self
    {
        $this->levelKey = $levelKey;
        $this->level = $level;
        return $this;
    }
}